{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "# Step 1: Pull Portfolio Factor Attribution Data with GS Quant\n",
    "\n",
    "## Authenticate and Initialize Your Session\n",
    "\n",
    "First you will import the necessary modules and add your client id and client secret."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "from IPython.display import display\n",
    "\n",
    "from gs_quant.markets.portfolio_manager import PortfolioManager\n",
    "from gs_quant.markets.report import FactorRiskUnit, FactorRiskTableMode\n",
    "from gs_quant.markets.securities import SecurityMaster, AssetIdentifier\n",
    "from gs_quant.session import GsSession, Environment\n",
    "\n",
    "client = None\n",
    "secret = None\n",
    "\n",
    "## External users must fill in their client ID and secret below and comment out the line below\n",
    "\n",
    "# client = 'ENTER CLIENT ID'\n",
    "# secret = 'ENTER CLIENT SECRET'\n",
    "\n",
    "GsSession.use(Environment.PROD, client_id=client, client_secret=secret)\n",
    "\n",
    "print('GS Session initialized.')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "## Step 2: Get Portfolio Factor Risk Report"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "risk_report = PortfolioManager('ENTER PORTFOLIO ID').get_factor_risk_report(\n",
    "    risk_model_id='ENTER RISK MODEL ID', benchmark_id=None\n",
    ")\n",
    "\n",
    "print(f'Factor risk report found with ID: {risk_report.id}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "Want to query data for an active risk report? Leverage the `SecurityMaster` class to retrieve the benchmark identifier and\n",
    "pass it into the `get_factor_risk_report` function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "benchmark = SecurityMaster.get_asset(id_value='SPX', id_type=AssetIdentifier.BLOOMBERG_ID)\n",
    "\n",
    "risk_report = PortfolioManager('ENTER PORTFOLIO ID').get_factor_risk_report(\n",
    "    risk_model_id='ENTER RISK MODEL ID', benchmark_id=benchmark.get_marquee_id()\n",
    ")\n",
    "\n",
    "print(f'Factor risk report found with ID: {risk_report.id}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "## Step 3: Get Current Portfolio Attribution\n",
    "\n",
    "Once your risk report is scheduled as of the latest business day, you can view updated attribution broken down by factor category:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "attr_data = risk_report.get_view(\n",
    "    start_date=risk_report.earliest_start_date, end_date=risk_report.latest_end_date, unit=FactorRiskUnit.Notional\n",
    ")\n",
    "category_table = attr_data.get('factorCategoriesTable')\n",
    "category_df = pd.DataFrame(category_table).filter(items=['name', 'pnl', 'minExposure', 'maxExposure', 'avgExposure'])\n",
    "\n",
    "display(category_df)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "It is also possible to get a similar table for all the factors in a factor category. In this case, let's drill down into the Style factors:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "factor_tables = attr_data.get('factorCategoryTables')\n",
    "factor_tables = [f for f in factor_tables if f.get('factorCategory') == 'Style']\n",
    "factor_df = pd.DataFrame(factor_tables[0].get('factors')).filter(\n",
    "    items=['name', 'pnl', 'minExposure', 'maxExposure', 'avgExposure']\n",
    ")\n",
    "\n",
    "display(factor_df)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "You can also generate a table that shows you the factor PnL over a date range at the asset level. Let's see the factor PnL for each asset for the factors Country, Beta, and Earnings Quality:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "pnl_table = risk_report.get_table(\n",
    "    mode=FactorRiskTableMode.Pnl,\n",
    "    start_date=risk_report.earliest_start_date,\n",
    "    end_date=risk_report.latest_end_date,\n",
    "    factors=[\n",
    "        \"Country\",\n",
    "        \"Beta\",\n",
    "        \"Earnings Quality\",\n",
    "    ],  # Skip passing in a value here to get a table with all model factors\n",
    ")\n",
    "\n",
    "display(pd.DataFrame(pnl_table))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "## Step 4: Historical Portfolio Factor Performance\n",
    "\n",
    "`get_factor_pnl` allows you to pull historical factor performance for a list of factors, as well as aggregations like factor, specific, and total risk:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "pnl = risk_report.get_factor_pnl(\n",
    "    factor_names=['Factor', 'Specific', 'Total', 'Market', 'Country', 'Industry', 'Style'],\n",
    "    start_date=risk_report.earliest_start_date,\n",
    "    end_date=risk_report.latest_end_date,\n",
    "    unit=FactorRiskUnit.Notional,\n",
    ")\n",
    "pnl_overview = pnl.filter(items=['Date', 'Total']).set_index('Date')\n",
    "\n",
    "pnl_overview.cumsum().plot(title='PnL')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "This makes it easy to break down PnL over time and how it was attributed to various systematic risk factors:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "pnl_overview = pnl.filter(items=['Date', 'Factor', 'Specific', 'Total']).set_index('Date')\n",
    "pnl_overview.cumsum().plot(title='PnL Overview')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "And dissect that further by factor attribution further by category..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "pnl_by_type = pnl.filter(items=['Date', 'Market', 'Country', 'Industry', 'Style', 'Specific']).set_index('Date')\n",
    "\n",
    "pnl_by_type.cumsum().plot(title='PnL by Factor Category')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "## Step 5: Historical Factor Exposure\n",
    "\n",
    "For each day, it's possible to pull your portfolio's exposure to specific factors..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "category_exposures = risk_report.get_factor_exposure(\n",
    "    factor_names=['Market', 'Industry', 'Style'],\n",
    "    start_date=risk_report.earliest_start_date,\n",
    "    end_date=risk_report.latest_end_date,\n",
    "    unit=FactorRiskUnit.Notional,\n",
    ").set_index('Date')\n",
    "\n",
    "category_exposures.plot(title='Exposures to Factor Categories')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "Or get the exposures to all factors in a given category:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "category_exposures = risk_report.get_factor_exposure(\n",
    "    factor_categories=['Style'],\n",
    "    start_date=risk_report.earliest_start_date,\n",
    "    end_date=risk_report.latest_end_date,\n",
    "    unit=FactorRiskUnit.Notional,\n",
    ").set_index('Date')\n",
    "\n",
    "category_exposures.plot(title='Exposures to Style Factors')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "*Other questions? Reach out to the [Portfolio Analytics team](mailto:gs-marquee-analytics-support@gs.com)!*"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
